package com.ifengxue.ioc.util;

import com.sun.istack.internal.NotNull;

import javax.annotation.Nullable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

/**
 * 注解工具
 *
 * @author LiuKeFeng
 * @date 2017-08-11
 */
public class AnnotationUtil {
    /**
     * 从当前方法出发到声明该方法的类来寻找注解
     * @param clazz
     * @param target
     * @param <A>
     * @return
     */
    @Nullable
    public static <A extends Annotation> A findNullableAnnotation(@NotNull Class<A> clazz, @NotNull Method target) {
        if (target.isAnnotationPresent(clazz)) {
            return target.getAnnotation(clazz);
        }
        return findNullableAnnotation(clazz, target.getDeclaringClass());
    }

    /**
     * 从当前类出发到继承的类来寻找注解
     * @param clazz
     * @param target
     * @param <A>
     * @return
     */
    @Nullable
    public static <A extends Annotation> A findNullableAnnotation(@NotNull Class<A> clazz, @NotNull Class<?> target) {
        while (target != null) {
            if (target.isAnnotationPresent(clazz)) {
                return target.getAnnotation(clazz);
            }
            target = target.getSuperclass();
        }
        return null;
    }

    /**
     * 查找在属性上添加了指定注解的注解中的一个或多个
     * @param clazz
     * @param annotationClasses 指定的注解数组
     * @return
     */
    public static List<Field> findAnnotatedFields(Class<?> clazz, Class<? extends Annotation>...annotationClasses) {
        List<Field> fields = new LinkedList<>();
        for (Field field : ClassUtil.findFields(clazz)) {
            for (Class<? extends Annotation> annotationClass : annotationClasses) {
                if (field.isAnnotationPresent(annotationClass)) {
                    fields.add(field);
                    break;
                }
            }
        }
        return fields;
    }

    /**
     * 检查指定的类是否包含了指定的注解中的一个或多个
     * @param clazz
     * @param annotationClasses 指定的注解集合
     * @return
     */
    public static boolean isAnnotatedClass(Class<?> clazz, Class<? extends Annotation>...annotationClasses) {
        for (Annotation annotation : clazz.getAnnotations()) {
            for (Class<? extends Annotation> annotationClass : annotationClasses) {
                if (annotation.getClass().equals(annotationClass)) {
                    return true;
                }
            }
        }
        return false;
    }
}
